{ 
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VL5sK3q7zx0K"
      },
      "source": [
        "Project Paper\n",
        "\n",
        "Project Owner: Aaron Emmanuel Xavier Sequeira\n",
        "\n",
        "Registration Number: 219302100\n",
        "\n",
        "B-tech in Information technology"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hg58xoC8bHMH"
      },
      "source": [
        "# 5 steps to implement a GAN\n",
        "\n",
        "  1. Define the GAN architecture basen on the dataset\n",
        "  2. Train the discriminator to distinguish real vs fake data\n",
        "  3. Train the generator to fake data that can fool the discriminator\n",
        "  4. Continue discriminator and generator training for multiple epochs\n",
        "  5. Save generator model to create new, realistic fake data"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "XmRNF_8PcdMM",
        "outputId": "0e5edc1a-f9f6-459b-9bb5-c788456b4812"
      },
      "outputs": [
        {
          "ename": "ModuleNotFoundError",
          "evalue": "No module named 'tensorflow'",
          "output_type": "error",
          "traceback": [
            "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[1;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
            "\u001b[1;32mc:\\Users\\aaron\\Desktop\\Aaron Important\\GitHub\\BP_Prediction-main\\BP_Prediction-main\\code\\GAN.ipynb Cell 3\u001b[0m line \u001b[0;36m3\n\u001b[0;32m      <a href='vscode-notebook-cell:/c%3A/Users/aaron/Desktop/Aaron%20Important/GitHub/BP_Prediction-main/BP_Prediction-main/code/GAN.ipynb#W2sZmlsZQ%3D%3D?line=0'>1</a>\u001b[0m \u001b[39m# Imports\u001b[39;00m\n\u001b[1;32m----> <a href='vscode-notebook-cell:/c%3A/Users/aaron/Desktop/Aaron%20Important/GitHub/BP_Prediction-main/BP_Prediction-main/code/GAN.ipynb#W2sZmlsZQ%3D%3D?line=2'>3</a>\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mlayers\u001b[39;00m \u001b[39mimport\u001b[39;00m Input, Dense, Reshape, Flatten\n\u001b[0;32m      <a href='vscode-notebook-cell:/c%3A/Users/aaron/Desktop/Aaron%20Important/GitHub/BP_Prediction-main/BP_Prediction-main/code/GAN.ipynb#W2sZmlsZQ%3D%3D?line=3'>4</a>\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mlayers\u001b[39;00m \u001b[39mimport\u001b[39;00m BatchNormalization\n\u001b[0;32m      <a href='vscode-notebook-cell:/c%3A/Users/aaron/Desktop/Aaron%20Important/GitHub/BP_Prediction-main/BP_Prediction-main/code/GAN.ipynb#W2sZmlsZQ%3D%3D?line=4'>5</a>\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mlayers\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39madvanced_activations\u001b[39;00m \u001b[39mimport\u001b[39;00m LeakyReLU\n",
            "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python39\\site-packages\\keras\\__init__.py:3\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[39m\"\"\"AUTOGENERATED. DO NOT EDIT.\"\"\"\u001b[39;00m\n\u001b[1;32m----> 3\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m \u001b[39mimport\u001b[39;00m __internal__\n\u001b[0;32m      4\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m \u001b[39mimport\u001b[39;00m activations\n\u001b[0;32m      5\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m \u001b[39mimport\u001b[39;00m applications\n",
            "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python39\\site-packages\\keras\\__internal__\\__init__.py:3\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[39m\"\"\"AUTOGENERATED. DO NOT EDIT.\"\"\"\u001b[39;00m\n\u001b[1;32m----> 3\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39m__internal__\u001b[39;00m \u001b[39mimport\u001b[39;00m backend\n\u001b[0;32m      4\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39m__internal__\u001b[39;00m \u001b[39mimport\u001b[39;00m layers\n\u001b[0;32m      5\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39m__internal__\u001b[39;00m \u001b[39mimport\u001b[39;00m losses\n",
            "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python39\\site-packages\\keras\\__internal__\\backend\\__init__.py:3\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[39m\"\"\"AUTOGENERATED. DO NOT EDIT.\"\"\"\u001b[39;00m\n\u001b[1;32m----> 3\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mbackend\u001b[39;00m \u001b[39mimport\u001b[39;00m _initialize_variables \u001b[39mas\u001b[39;00m initialize_variables\n\u001b[0;32m      4\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mbackend\u001b[39;00m \u001b[39mimport\u001b[39;00m track_variable\n",
            "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python39\\site-packages\\keras\\src\\__init__.py:21\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[39m# Copyright 2015 The TensorFlow Authors. All Rights Reserved.\u001b[39;00m\n\u001b[0;32m      2\u001b[0m \u001b[39m#\u001b[39;00m\n\u001b[0;32m      3\u001b[0m \u001b[39m# Licensed under the Apache License, Version 2.0 (the \"License\");\u001b[39;00m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[39m# limitations under the License.\u001b[39;00m\n\u001b[0;32m     14\u001b[0m \u001b[39m# ==============================================================================\u001b[39;00m\n\u001b[0;32m     15\u001b[0m \u001b[39m\"\"\"Implementation of the Keras API, the high-level API of TensorFlow.\u001b[39;00m\n\u001b[0;32m     16\u001b[0m \n\u001b[0;32m     17\u001b[0m \u001b[39mDetailed documentation and user guides are available at\u001b[39;00m\n\u001b[0;32m     18\u001b[0m \u001b[39m[keras.io](https://keras.io).\u001b[39;00m\n\u001b[0;32m     19\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m---> 21\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m \u001b[39mimport\u001b[39;00m applications\n\u001b[0;32m     22\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m \u001b[39mimport\u001b[39;00m distribute\n\u001b[0;32m     23\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m \u001b[39mimport\u001b[39;00m models\n",
            "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python39\\site-packages\\keras\\src\\applications\\__init__.py:18\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[39m# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\u001b[39;00m\n\u001b[0;32m      2\u001b[0m \u001b[39m#\u001b[39;00m\n\u001b[0;32m      3\u001b[0m \u001b[39m# Licensed under the Apache License, Version 2.0 (the \"License\");\u001b[39;00m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[39m# limitations under the License.\u001b[39;00m\n\u001b[0;32m     14\u001b[0m \u001b[39m# ==============================================================================\u001b[39;00m\n\u001b[0;32m     15\u001b[0m \u001b[39m\"\"\"Keras Applications are premade architectures with pre-trained weights.\"\"\"\u001b[39;00m\n\u001b[1;32m---> 18\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mapplications\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mconvnext\u001b[39;00m \u001b[39mimport\u001b[39;00m ConvNeXtBase\n\u001b[0;32m     19\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mapplications\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mconvnext\u001b[39;00m \u001b[39mimport\u001b[39;00m ConvNeXtLarge\n\u001b[0;32m     20\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mapplications\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mconvnext\u001b[39;00m \u001b[39mimport\u001b[39;00m ConvNeXtSmall\n",
            "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python39\\site-packages\\keras\\src\\applications\\convnext.py:26\u001b[0m\n\u001b[0;32m     17\u001b[0m \u001b[39m\"\"\"ConvNeXt models for Keras.\u001b[39;00m\n\u001b[0;32m     18\u001b[0m \n\u001b[0;32m     19\u001b[0m \u001b[39mReferences:\u001b[39;00m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     22\u001b[0m \u001b[39m  (CVPR 2022)\u001b[39;00m\n\u001b[0;32m     23\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[0;32m     25\u001b[0m \u001b[39mimport\u001b[39;00m \u001b[39mnumpy\u001b[39;00m \u001b[39mas\u001b[39;00m \u001b[39mnp\u001b[39;00m\n\u001b[1;32m---> 26\u001b[0m \u001b[39mimport\u001b[39;00m \u001b[39mtensorflow\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mcompat\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mv2\u001b[39;00m \u001b[39mas\u001b[39;00m \u001b[39mtf\u001b[39;00m\n\u001b[0;32m     28\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m \u001b[39mimport\u001b[39;00m backend\n\u001b[0;32m     29\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mkeras\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39msrc\u001b[39;00m \u001b[39mimport\u001b[39;00m initializers\n",
            "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'tensorflow'"
          ]
        }
      ],
      "source": [
        "# Imports\n",
        "\n",
        "from keras.layers import Input, Dense, Reshape, Flatten\n",
        "from keras.layers import BatchNormalization\n",
        "from keras.layers.advanced_activations import LeakyReLU\n",
        "from keras.models import Sequential, Model\n",
        "from tensorflow.keras.optimizers import Adam\n",
        "from tensorflow.keras.utils import plot_model\n",
        "from tensorflow.keras.callbacks import Callback\n",
        "\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import tensorflow as tf\n",
        "import time\n",
        "\n",
        "import sys\n",
        "import os\n",
        "import numpy as np\n",
        "from tqdm import tqdm\n",
        "import scipy.io as sio\n",
        "import pandas as pd\n",
        "\n",
        "print(tf.__version__)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-Y8zui1tAL4-"
      },
      "source": [
        "# Connecting to Google Drive and loading the data"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "XyCIuqYhAFey",
        "outputId": "101ff74c-dbb1-4d52-8a1b-6c6770bbc911"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Mounted at /gdrive\n"
          ]
        }
      ],
      "source": [
        "from google.colab import drive\n",
        "drive.mount('/gdrive', force_remount=True)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "-c3XUP9pALOL",
        "outputId": "7551a10f-f302-4b3d-99ea-92e5f029c0fc"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Available data ['Samples', 'part_12.mat', 'part_10.mat', 'part_11.mat', 'part_1.mat', 'part_3.mat', 'part_2.mat', 'part_4.mat', 'part_5.mat', 'part_7.mat', 'part_6.mat', 'part_8.mat', 'part_9.mat', 'Divided_CSV_Files', '.ipynb_checkpoints', 'generator_model_1K.h5', 'generator_model_5K.h5', 'generator_model_2K.h5', 'generator_model_4K.h5', 'generator_model_10K.h5', 'generator_model_2_9K.h5']\n",
            "Number of files 21\n"
          ]
        }
      ],
      "source": [
        "data_path = '/gdrive/MyDrive/Project_Dataset'\n",
        "print('Available data', os.listdir(data_path))\n",
        "print('Number of files', len(os.listdir(data_path)))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "XGZm_P8OBEMc",
        "outputId": "0de389a3-0a20-4c11-9e40-d3e900f50787"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Number of samples: 12000\n"
          ]
        }
      ],
      "source": [
        "mats_list = []\n",
        "for i in range(1, 13):\n",
        "  current_mat_str = '/gdrive/MyDrive/Project_Dataset/part_' + str(i) + '.mat'\n",
        "  mats_list.append(sio.loadmat(current_mat_str)['p'][0])\n",
        "\n",
        "data = np.concatenate(mats_list)\n",
        "total_number_of_samples = len(data)\n",
        "print(f\"Number of samples: {total_number_of_samples}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "TBBa4VpKCVej"
      },
      "outputs": [],
      "source": [
        "# Free the memory\n",
        "del mats_list"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "k-hVxBzfnTgs"
      },
      "outputs": [],
      "source": [
        "# Split data\n",
        "\n",
        "ppg = []\n",
        "abp = []\n",
        "ecg = []\n",
        "\n",
        "for sample in data:\n",
        "  ppg.append(sample[0][:1000])\n",
        "  abp.append(sample[1][:1000])\n",
        "  ecg.append(sample[2][:1000])\n",
        "\n",
        "pd.DataFrame(ppg).to_csv('/gdrive/MyDrive/Divided_CSV_Files/ppg.csv', index_label=False)\n",
        "pd.DataFrame(abp).to_csv('/gdrive/MyDrive/Divided_CSV_Files/abp.csv', index_label=False)\n",
        "pd.DataFrame(ecg).to_csv('/gdrive/MyDrive/Divided_CSV_Files/ecg.csv', index_label=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OHt3q0DhnWib"
      },
      "outputs": [],
      "source": [
        "ppg = pd.read_csv('/gdrive/MyDrive/Divided_CSV_Files/ppg.csv')\n",
        "abp = pd.read_csv('/gdrive/MyDrive/Divided_CSV_Files/abp.csv')\n",
        "ecg = pd.read_csv('/gdrive/MyDrive/Divided_CSV_Files/ecg.csv')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "rpIgk82FnZGw",
        "outputId": "0724efba-e5e4-4673-f5b9-5c42c250fab8"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "(9600, 1000, 2) (9600, 1000)\n"
          ]
        }
      ],
      "source": [
        "data = np.stack((ppg, ecg), axis=-1)\n",
        "X_train = data[:9600]\n",
        "X_val = data[9600:10800]\n",
        "X_test = data[10800:]\n",
        "\n",
        "y_train = abp[:9600]\n",
        "y_val = abp[9600:10800]\n",
        "y_test = abp[10800:]\n",
        "\n",
        "print(X_train.shape, y_train.shape)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "1RPiEPDWncdm",
        "outputId": "0b828d91-ca5b-4835-bc88-4d2cee2aa57b"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "-7.49609375\n",
            "4.5\n"
          ]
        }
      ],
      "source": [
        "# getting the global max and min values becuase we'll need them\n",
        "# for a normalization later\n",
        "\n",
        "min_X_train = np.min(X_train)\n",
        "max_X_train = np.max(X_train)\n",
        "\n",
        "print(min_X_train)\n",
        "print(max_X_train)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "diY7euPsgIQZ"
      },
      "source": [
        "# GAN Code Implementation"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "r81D2Jab-dpM"
      },
      "outputs": [],
      "source": [
        "# Defining global constants\n",
        "\n",
        "signal_shape = (1000, 2)\n",
        "d_loss_list = []\n",
        "g_loss_list = []\n",
        "epoch_times = []"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eYbIWdHiiCnE"
      },
      "source": [
        "How LeakyReLu works\n",
        "\n",
        "![image.png]()\n",
        "\n",
        "* The alpha parameter in the following implementation represents how large the angle with the x-axis is."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nAlFxjBcgLdU"
      },
      "outputs": [],
      "source": [
        "def build_generator():\n",
        "\n",
        "    # Defining the constants\n",
        "    alpha_val = 0.2\n",
        "    momentum_val = 0.8\n",
        "    number_of_dense_layers = 3\n",
        "    initial_dense_layer_neurons = 256\n",
        "    \n",
        "    # Initializing the dense layers for the generator\n",
        "\n",
        "    dense_layers = []\n",
        "    for i in range(number_of_dense_layers):\n",
        "      dense_layers.append(initial_dense_layer_neurons << i)\n",
        "\n",
        "    # 1D array of size 100 (latent vector / noise)\n",
        "    noise_shape = (100, )\n",
        "\n",
        "\n",
        "    # Step 1: Define the GAN architecture basen on the dataset      \n",
        "    model = Sequential()\n",
        "\n",
        "    # Adding 'number_of_dense_layers' sets of:\n",
        "    # (dense layer, LeakyReLu, BatchNormalization)\n",
        "    for i, dense_layer_neurons_number in enumerate(dense_layers):\n",
        "      model.add(Dense(dense_layer_neurons_number)) if not i == 0 else model.add(Dense(dense_layer_neurons_number, input_shape=noise_shape))\n",
        "      model.add(LeakyReLU(alpha=alpha_val))\n",
        "      model.add(BatchNormalization(momentum=momentum_val))\n",
        "    \n",
        "    # Adding a final dense layer\n",
        "    model.add(Dense(np.prod(signal_shape), activation='tanh'))\n",
        "    model.add(Reshape(signal_shape))\n",
        "\n",
        "    model.build(input_shape=signal_shape)\n",
        "    model.summary()\n",
        "\n",
        "    noise = Input(shape=noise_shape)\n",
        "    signal = model(noise)    # Generated signal\n",
        "\n",
        "    return Model(noise, signal)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "iSDWPjfgFuTL"
      },
      "outputs": [],
      "source": [
        "def build_discriminator():\n",
        "\n",
        "    # Defining the constants\n",
        "    alpha_val = 0.2\n",
        "    dense_layers = [512, 256]\n",
        "\n",
        "    model = Sequential()\n",
        "\n",
        "    model.add(Flatten(input_shape=signal_shape))\n",
        "\n",
        "    for dense_layer_neurons_number in dense_layers:\n",
        "      model.add(Dense(dense_layer_neurons_number))\n",
        "      model.add(LeakyReLU(alpha=alpha_val))\n",
        "    \n",
        "    model.add(Dense(1, activation='sigmoid'))\n",
        "    model.summary()\n",
        "\n",
        "    signal = Input(shape=signal_shape)\n",
        "    validity = model(signal)\n",
        "\n",
        "    return Model(signal, validity)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nC9NCImnGg8X"
      },
      "outputs": [],
      "source": [
        "def normalization(num):\n",
        "  k = 2 / (max_X_train - min_X_train)\n",
        "  m = (- min_X_train - max_X_train) / (max_X_train - min_X_train)\n",
        "  norm = k * num + m\n",
        "  return norm\n",
        "\n",
        "\n",
        "for sample in X_train:\n",
        "  for arr in sample:\n",
        "    arr[0] = normalization(arr[0])\n",
        "    arr[1] = normalization(arr[1])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "mB2uMAUwnqh2"
      },
      "outputs": [],
      "source": [
        "def train(epochs, batch_size=128):\n",
        "\n",
        "    half_batch = int(batch_size / 2)\n",
        "\n",
        "    # Now we start iterating over the epochs and training both our discriminator\n",
        "    # and generator, one after another. We train the discriminator first, by\n",
        "    # feeding it real data (the half_batch) then training the generator with \n",
        "    # both real and fake data (separately). After that, we compute the loss and\n",
        "    # continue to iterate until both the generator and discriminator have been trained.\n",
        "    for epoch in tqdm(range(epochs)):\n",
        "\n",
        "        # Save the times so we can analyze them after\n",
        "        initial_time_for_epoch = time.clock()\n",
        "\n",
        "        #  Train Discriminator\n",
        "\n",
        "        # Select a random half batch of real images\n",
        "        idx = np.random.randint(0, X_train.shape[0], half_batch)\n",
        "        signals = X_train[idx]\n",
        "\n",
        "        noise = np.random.normal(0, 1, (half_batch, 100))\n",
        "\n",
        "        # Generate a half batch of fake signals\n",
        "        gen_signals = generator.predict(noise)\n",
        "\n",
        "        # Train the discriminator on real and fake signals, separately\n",
        "\n",
        "        d_loss_real = discriminator.train_on_batch(signals, np.ones((half_batch, 1)))\n",
        "        d_loss_fake = discriminator.train_on_batch(gen_signals, np.zeros((half_batch, 1)))\n",
        "        \n",
        "        # calculate the average square error of the real & false predictions\n",
        "        d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) \n",
        "\n",
        "        # Now it's time to train our generator. Its idea is to 'fool' the discriminator\n",
        "        # meaning that we're trying to get the discriminator to mark the fake signals\n",
        "        # as real and vice-versa\n",
        "\n",
        "        # Create noise vectors as input for generator.\n",
        "        noise = np.random.normal(0, 1, (batch_size, 100))\n",
        "\n",
        "        # The generator wants the discriminator to label the generated samples\n",
        "        # as valid (true i.e. one)\n",
        "        # This is where the genrator is trying to trick discriminator into believing\n",
        "        # the generated image is true (hence value of true (one) for y)\n",
        "        valid_y = np.array([1] * batch_size)\n",
        "\n",
        "        # Now get the general loss by training both at the same time\n",
        "        g_loss = combined.train_on_batch(noise, valid_y)\n",
        "\n",
        "\n",
        "        # In order to have some type of logging, we print the data\n",
        "        print (f\"{epoch} [D loss: {d_loss[0]}] [G loss: {g_loss}]\")\n",
        "        \n",
        "        d_loss_list.append(d_loss[0])\n",
        "        g_loss_list.append(g_loss)\n",
        "\n",
        "        if epochs % 1000 == 0:\n",
        "          number_of_thousands = int(epochs / 1000)\n",
        "          discriminator_weights_file = f'/gdrive/MyDrive/BMEN_4470_Fall_2021/Final Project/GAN_Weights/discriminator_{number_of_thousands}K'\n",
        "          generator_weights_file = f'/gdrive/MyDrive/BMEN_4470_Fall_2021/Final Project/GAN_Weights/discriminator_{number_of_thousands}K'\n",
        "          discriminator.save_weights(discriminator_weights_file)\n",
        "          generator.save_weights(generator_weights_file)\n",
        "        \n",
        "        end_time_for_epoch = time.clock()\n",
        "        epoch_times.append(end_time_for_epoch - initial_time_for_epoch)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UPcKOkVrD9ga"
      },
      "outputs": [],
      "source": [
        "# Adding a timer callback to track the time\n",
        "\n",
        "class timecallback(Callback):\n",
        "    def __init__(self):\n",
        "        self.times = []\n",
        "        # use this value as reference to calculate cummulative time taken\n",
        "        self.timetaken = time.clock()\n",
        "    def on_epoch_end(self,epoch,logs = {}):\n",
        "        self.times.append((epoch,time.clock() - self.timetaken))\n",
        "    def on_train_end(self,logs = {}):\n",
        "        plt.xlabel('Epoch')\n",
        "        plt.ylabel('Total time taken until an epoch in seconds')\n",
        "        plt.plot(*zip(*self.times))\n",
        "        plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "background_save": true
        },
        "id": "B7867ho_nsoJ"
      },
      "outputs": [],
      "source": [
        "optimizer = Adam(0.0002, 0.5)\n",
        "\n",
        "discriminator = build_discriminator()\n",
        "discriminator.compile(loss='binary_crossentropy',\n",
        "                      optimizer=optimizer,\n",
        "                      metrics=['accuracy'])\n",
        "\n",
        "generator = build_generator()\n",
        "generator.compile(loss='binary_crossentropy', optimizer=optimizer)\n",
        "\n",
        "z = Input(shape=(100,))\n",
        "signal = generator(z)\n",
        "\n",
        "discriminator.trainable = False\n",
        "valid = discriminator(signal)\n",
        "\n",
        "combined = Model(z, valid)\n",
        "combined.compile(loss='binary_crossentropy', optimizer=optimizer)\n",
        "\n",
        "# timetaken = timecallback()\n",
        "\n",
        "train(epochs=10000, batch_size=32)\n",
        "generator.save('/gdrive/MyDrive/BMEN_4470_Fall_2021/Final Project/Final_Project_Dataset/generator_model_10K.h5')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ShMdZEJOxitM"
      },
      "outputs": [],
      "source": [
        "from keras.models import load_model\n",
        "\n",
        "noise_to_predict = np.random.normal(0, 1, (32, 100))\n",
        "# Load the model if needed\n",
        "# generator = load_model('/gdrive/MyDrive/generator_model_10K.h5')\n",
        "\n",
        "# Make a prediction\n",
        "generated_signal = generator.predict(noise_to_predict)\n",
        "print(generated_signal.shape)\n",
        "\n",
        "# Plot the time per epoch needed\n",
        "plt.plot(epoch_times[:])\n",
        "plt.plot(generated_signal[4, 700:750])\n",
        "\n",
        "# Plot the loss values for the discriminator and generator\n",
        "plt.plot(d_loss_list[:])\n",
        "plt.plot(g_loss_list[:])\n",
        "\n",
        "\n",
        "# Get the min difference between discriminator and generator loss values\n",
        "min_loss = 20\n",
        "min_i = 0\n",
        "for i in range(500, 2900):\n",
        "  if min_loss > abs(d_loss_list[i] - g_loss_list[i]):\n",
        "    min_loss = abs(d_loss_list[i] - g_loss_list[i])\n",
        "    min_i = i\n",
        "\n",
        "\n",
        "print(min_loss, min_i)"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [],
      "name": "BMEN4470_Fall_2021_Final_Project.ipynb.txt",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.9.13"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
